/*
 * Source code written by Tácio S. Diogo.
 * Email: taciosd@gmail.com
 * Any copy or use without permission is prohibited.
 */
package app.modelo;

import app.reputacao.ACAO;
import app.agentes.Agente;
import app.agentes.Cidadao;
import app.agentes.JuizTse;
import jade.core.AID;
import jade.core.Agent;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Tácio S. Diogo
 */
public class Ambiente {
    private static Ambiente instance;
    private volatile boolean eleicoesIniciadas = false;
    private volatile Map<String, Propaganda> propagandas;
    private volatile JuizTse juiz;
    private volatile ArrayList<Cidadao> agentes = new ArrayList<Cidadao>();
    
    public static synchronized Ambiente getInstance() {
        if (instance == null) {
            instance = new Ambiente();
        }
        return instance;
    }
    
    protected Ambiente() {
        propagandas = new HashMap<String, Propaganda>();
    }
    
    public void executarAcao(Agente agente, ACAO acao) {
        if (acao.equals(ACAO.INICIAR_ELEICAO)) {
            eleicoesIniciadas = true;
            Calendar dataInicioSimulacao = Calendar.getInstance();
            juiz = (JuizTse)agente;
            juiz.setDataInicioSimulacao(dataInicioSimulacao);
        }
        
        if (eleicoesIniciadas) {
            verificarCadastro(agente);
            executar(agente, acao);
        }
    }
    
    private void executar(Agent agent, ACAO acao) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(Ambiente.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        Console.escrever(agent, acao.toString());
        Agente agente = (Agente)agent;
        
        switch (acao) {
            case CAMINHAR:
                agente.setPropagandaAtual(getPropagandaAleatoria());
                break;
            case PROPAGANDA:
                Propaganda propaganda = agente.getPropagandaAtual();
                adicionarPropaganda(propaganda);
                Console.escrever("Propaganda realizada: " + propaganda.getMensagem());
                break;
            case TERMINAR_ELEICAO:
                eleicoesIniciadas = false;
                Console.escrever("As eleicoes terminaram!!");
            default:
                break;
        }
    }
    
    private void adicionarPropaganda(Propaganda propaganda) {
        Calendar cal = null;
        String nomeAgente = propaganda.getCandidato().getLocalName();
        propagandas.put(nomeAgente, propaganda);
    }
    
    private Propaganda getPropagandaAleatoria() {
        int escolha = (int) (Math.random() % 2);
        boolean temPropagandaProxima = ((escolha == 0) ? true : false);
        if (temPropagandaProxima) {
            Collection listaPropagandas = propagandas.values();
            Object[] arrayPropagandas = listaPropagandas.toArray();
            int size = arrayPropagandas.length;
            Propaganda propagandaEscolhida = null;
            
            if (size > 0) {
                Random rnd = new Random();
                int pos = Math.abs(rnd.nextInt()) % size;
                propagandaEscolhida = (Propaganda) arrayPropagandas[pos];
            }
            
            return propagandaEscolhida;
        }
        
        return null;
    }

    public AID getJuizAid() {
        return juiz.getAID();
    }

    private void verificarCadastro(Agente agente) {
        if (! (agente instanceof Cidadao)) {
            return;
        }
        
        Cidadao cidadao = (Cidadao) agente;
        if (!agentes.contains(cidadao)) {
            agentes.add(cidadao);
        }
    }
    
    public List<Cidadao> getCidadaos(){
        return agentes;
    }
    
    public List<Cidadao> getCidadaos(int numAgentes) {
        if (numAgentes > agentes.size() || (numAgentes == 0)) {
            return agentes;
        }
        
        List<Cidadao> cidadaos = new ArrayList<Cidadao>();
        
        Random rnd = new Random();
        int pos = rnd.nextInt(agentes.size());
        
        int agentesEscolhidos = 0;
        while (pos != -1) {
            Cidadao cidadao = agentes.get(pos);
            cidadaos.add(cidadao);
            agentesEscolhidos++;
            
            if (agentesEscolhidos == numAgentes) {
                pos = -1;
            } else {
                pos++;
                if (pos > (agentes.size()-1)) {
                    pos = 0;
                }
            }
        }
        
        return cidadaos;
    }
}
